home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
general
/
visulztn
/
saoimage
/
saoimage.lha
/
crdtemp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-06-21
|
9KB
|
283 lines
#ifndef lint
static char SccsId[] = "%W% %G%";
#endif
/* Module: crdtemp.c (Coordinate Temporary)
* Purpose: Calculate display coordinates for pan and zoom
* Subroutine: set_tdisp() returns: void
* Subroutine: reset_tdisp() returns: void
* Subroutine: set_disptran() returns: void
* Subroutine: panedge_zoom() returns: void
* Subroutine: set_dispoff() returns: void
* Xlib calls: none
* Copyright: 1988 Smithsonian Astrophysical Observatory
* You may do anything you like with this file except remove
* this copyright. The Smithsonian Astrophysical Observatory
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
* Modified: {0} Michael VanHilst initial version 1 September 1988
* {1} MVH Kludged set_dispoff to trap overrrun 28 April 1990
* {n} <who> -- <does what> -- <when>
*/
#include <stdio.h> /* stderr, NULL, etc */
#include "hfiles/coord.h" /* coord structs */
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
/*
* Subroutine: set_tdisp
* Purpose: set needed parameters for proposed display
* PreState: tid.cenX, tid.cenY, tid.zoom, and tid.block must be set
*/
void set_tdisp ( coord )
struct coordRec *coord;
{
/* calculate corners of display in img coords */
/* 0.5 accounts for rounding to nearest pixel, 0.499 rounding at limit */
coord->tid.srcX1 = (int)
(coord->tid.cenX - ((coord->disp.cenX - 0.5) / coord->tid.zoom));
coord->tid.srcX2 = (int)
(coord->tid.cenX +
((0.499 + (float)coord->disp.width - coord->disp.cenX) /
coord->tid.zoom));
coord->tid.srcY1 = (int)
(coord->tid.cenY - ((coord->disp.cenY - 0.5) / coord->tid.zoom));
coord->tid.srcY2 = (int)
(coord->tid.cenY +
((0.499 + (float)coord->disp.height - coord->disp.cenY) /
coord->tid.zoom));
/* limit display area to img area */
coord->tid.clip = 0;
if( coord->tid.srcX1 < coord->img.X1i ) {
coord->tid.srcX1 = coord->img.X1i;
coord->tid.clip += LX;
}
if( coord->tid.srcX2 > coord->img.X2i ) {
coord->tid.srcX2 = coord->img.X2i;
coord->tid.clip += RX;
}
if( coord->tid.srcY1 < coord->img.Y1i ) {
coord->tid.srcY1 = coord->img.Y1i;
coord->tid.clip += TY;
}
if( coord->tid.srcY2 > coord->img.Y2i ) {
coord->tid.srcY2 = coord->img.Y2i;
coord->tid.clip += BY;
}
/* check display parameters against buf contents */
if( coord->bufcheck ) {
/* request outside coverage of buffer contents */
if( (coord->tid.srcX1 < coord->ib.srcX1) ||
(coord->tid.srcX2 > coord->ib.srcX2) ||
(coord->tid.srcY1 < coord->ib.srcY1) ||
(coord->tid.srcY2 > coord->ib.srcY2) )
coord->buferror = 1;
else if( coord->ib.block != 1 ) {
if( coord->tid.block < coord->ib.block )
/* request for finer resolution than currently in buffer */
coord->buferror = 1;
else if( ((int)coord->tid.block % coord->ib.block) != 0 )
/* request for incompatible blocking */
coord->buferror = 1;
else
coord->buferror = 0;
} else
coord->buferror = 0;
}
}
/*
* Subroutine: reset_tdisp
* Purpose: Reset temp disp proposal to the current disp params
*/
void reset_tdisp ( coord )
struct coordRec *coord;
{
bcopy((char *)&coord->id, (char *)&coord->tid, sizeof(Edges));
coord->buferror = 0;
}
/*
* Subroutine: set_disptran
* Purpose: Set display parameters and translations as per temp
*/
void set_disptran ( coord )
struct coordRec *coord;
{
void set_transform(), combine_transform(), invert_transform();
bcopy((char *)&coord->tid, (char *)&coord->id, sizeof(Edges));
/* compute coordinate conversions between pan and img systems */
set_transform(coord->id.cenX, coord->id.cenY, coord->id.zoom,
&coord->disp, &coord->img,
&coord->disptoimg, &coord->imgtodisp);
/* compute transform from display to file and the reverse */
combine_transform(&coord->disptofile,
&coord->disptoimg, &coord->imgtofile);
invert_transform(&coord->filetodisp, &coord->disptofile,
(double)coord->file.ioff);
}
/*
* Subroutine: panedge_zoom
* Purpose: set up zoom given edges of desired display and
* appropriate img transform
*/
void panedge_zoom ( coord, wintoimgtrans, win_x, win_y )
struct coordRec *coord; /* i: collected coords */
Transform *wintoimgtrans; /* i: transform from mouse's window to img */
int win_x, win_y; /* i: window coords of mouse event */
{
float imgX, imgY;
int box_width, box_height;
void i_transform();
static int choose_zoom();
/* calculate image coordinates of win_x and win_y */
i_transform(wintoimgtrans, win_x, win_y, &imgX, &imgY);
/* select zoom based on this box */
box_width = abs((int)coord->tid.cenX - (int)imgX) * 2 + 1;
box_height = abs((int)coord->tid.cenY - (int)imgY) * 2 + 1;
coord->tid.block = choose_zoom(coord->disp.width, coord->disp.height,
box_width, box_height);
/* check against already generous limits and set float zoom factor */
if( coord->tid.block > 0 ) {
if( coord->tid.block > 400 )
coord->tid.block = 400;
coord->tid.zoom = 1.0 / (double)coord->tid.block;
} else {
if( coord->tid.block < -100 )
coord->tid.block = -100;
coord->tid.zoom = -(double)coord->tid.block;
}
}
/*
* Subroutine: choose_zoom
* Purpose: Select the zoom to best fit indicated image subsection to
* display window
* Method: Choose a zoom which comes closest to putting the ref point
* on an edge while still enclosing it
* Returns: Source-to-dest integer blocking code
*/
static int choose_zoom ( dst_width, dst_height, src_width, src_height )
int dst_width; /* width of window */
int dst_height; /* height of window */
int src_width; /* width of image section */
int src_height; /* height of image section */
{
int i;
/* limit width and height just in case */
src_width = MAX(1, src_width);
src_height = MAX(1, src_height);
#ifdef DEBUG
if( (dst_width <= 0) || (dst_height <= 0) ) {
(void)fprintf(stderr, "WARNING: no window size for choose_zoom\n");
return(1.0);
}
#endif
/* will we zoom up or down */
/* if source image section has more pixels than destination, block */
if( (src_width > dst_width) || (src_height > dst_height) ) {
/* point is outside zoom-1 frame, enlarge source until we include it */
for( i = 1;
(((dst_width * i) <= src_width) || ((dst_height * i) <= src_height));
i++ );
return( i );
} else {
/* point is inside zoom-one frame */
/* try shrinking source until we no-longer include it, then back-up one */
/* (count until we reach a point where one error changes sign) */
for( i = 1;
(((src_width * i) <= dst_width) &&
((src_height * i) <= dst_height));
i++ );
if( --i == 1 ) return(1);
else return( -i );
}
}
/*
* Subroutine: set_dispoff
* Purpose: Set the special window (dest) coords for mapping a display
* Note: Round pixel index in if on an edge between pixels
* Note: A is src (buf), B is dst (disp)
*/
void set_dispoff ( BAtrans, Bsys, AB )
Transform *BAtrans;
Coordsys *Bsys;
Edges *AB;
{
float x, y;
int BAblock;
/* Compute simple coords for simplified display routines */
x = -BAtrans->add_outx / BAtrans->inx_outx;
if( x < 0 )
AB->dst_x = (int)(x - 0.5);
else
AB->dst_x = (int)(x + 0.5);
y = -BAtrans->add_outy / BAtrans->iny_outy;
if( y < 0 )
AB->dst_y = (int)(y - 0.5);
else
AB->dst_y = (int)(y + 0.5);
d_transform(BAtrans, 0.0, 0.0, &x, &y);
if( x < 0 )
AB->src_x = (int)(x - 0.5);
else
AB->src_x = (int)(x + 0.5);
if( x < 0 )
AB->src_y = (int)(y - 0.5);
else
AB->src_y = (int)(y + 0.5);
/* Compute [not completely correctly] paramaters for old display code */
BAblock = -AB->block;
/* do coords for top-left corner */
if( (BAblock > 0) || ((AB->clip & LXTY) != 0) ) {
/* calculate upperleft edge backwards through transform */
x = ((float)AB->srcX1 - BAtrans->add_outx) / BAtrans->inx_outx;
y = ((float)AB->srcY1 - BAtrans->add_outy) / BAtrans->iny_outy;
AB->dstX1 = (int)(x + 0.001);
AB->dstY1 = (int)(y + 0.001);
if( AB->dstX1 < Bsys->X1i )
AB->dstX1 = Bsys->X1i;
if( AB->dstY1 < Bsys->Y1i )
AB->dstY1 = Bsys->Y1i;
} else {
/* block 1 or less */
AB->dstX1 = Bsys->X1;
AB->dstY1 = Bsys->Y1;
}
if( (BAblock > 0) || ((AB->clip & RXBY) != 0) ) {
/* calculate lowerright edge backwards through transform */
x = ((float)(AB->srcX2 + 1) - BAtrans->add_outx) / BAtrans->inx_outx;
y = ((float)(AB->srcY2 + 1) - BAtrans->add_outy) / BAtrans->iny_outy;
AB->dstX2 = (int)(x - 0.001);
AB->dstY2 = (int)(y - 0.001);
if( AB->dstX2 > Bsys->X2i )
AB->dstX2 = Bsys->X2i;
if( AB->dstY2 > Bsys->Y2i )
AB->dstY2 = Bsys->Y2i;
} else {
AB->dstX2 = Bsys->X2;
AB->dstY2 = Bsys->Y2;
}
AB->dstXwdth = 1 + AB->dstX2 - AB->dstX1;
AB->dstYhght = 1 + AB->dstY2 - AB->dstY1;
/* kludge trap to prevent algorithm from overshooting image buffer */
if( (BAtrans->inx_outx >= 1.0) &&
((AB->dstXwdth * BAtrans->inx_outx) > AB->srcXwdth) ) {
AB->dstX2--;
AB->dstXwdth--;
}
if( (BAtrans->iny_outy >= 1.0) &&
((AB->dstYhght * BAtrans->iny_outy) > AB->srcYhght) ) {
AB->dstY2--;
AB->dstYhght--;
}
}